package com.gitee.wsl.jvm.service.download

import com.gitee.wsl.ext.K
import com.gitee.wsl.ext.runOnScope
import com.gitee.wsl.jvm.service.download.DownloadProgress.Companion.changeProgress
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import okio.IOException
import timber.log.Timber
import java.io.File
import java.io.InputStream
import java.io.RandomAccessFile

internal class DownloadRunnable(
    private val mUrl: String,
    private val mFile: File,
    private val mProgress: DownloadProgress,
    private val mThreadId: Int,
    private val mStart: Long,
    private val mEnd: Long,
    private val mCallback: DownloadCallback
) : Runnable {

    override fun run() {
        val request = Request.Builder()
            .url(mUrl).addHeader("Range", "btyes=$mStart-$mEnd").build()
        val response: Response = try {
            OkHttpClient().newCall(request).execute()
        } catch (e: IOException) {
            e.printStackTrace()
            Timber.e("下载异常:" + e.message)
            postFailure(e)
            return
        }
        val code = response.code
        if (code == 404 || code > 500) {
            postFailure(IllegalStateException("Server exception"))
            return
        }
        val body = response.body
        if (body == null) {
            postFailure(NullPointerException("body be empty"))
            return
        }
        var inputStream: InputStream? = null
        inputStream = body.byteStream()
        download(inputStream, response.body!!)
    }

    private fun download(inputStream: InputStream, body: ResponseBody) {
        //只读写我们自己的内容
        var accessFile: RandomAccessFile? = null
        mProgress.status = DownloadProgress.LOADING
        try {
            accessFile = RandomAccessFile(mFile, "rwd")
            //从什么位置开始写
            accessFile.seek(mStart)
            var len: Int
            val buffer = ByteArray(1024 * 100)
            while (inputStream.read(buffer).also { len = it } != -1 && mProgress.status == DownloadProgress.LOADING) {
                accessFile.write(buffer, 0, len)
                changeProgress(mProgress, len * 2.toLong(), mProgress.totalSize, object :
                    DownloadProgress.Action {
                    override fun call(progress: DownloadProgress?) {
                        mCallback.onProgress((progress!!.fraction * 100).toInt())
                    }
                })
            }
            mCallback.onSucceed(mFile)
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            inputStream.close()
            accessFile?.close()
        }
    }

    private fun postFinish(file: File) {
        mProgress.fraction = 1.0f
        mProgress.status = DownloadProgress.FINISH
        K.runOnScope(K.MAIN) {  mCallback.onSucceed(file) }
    }

    private fun postFailure(e: Exception) {
        mProgress.status = DownloadProgress.FAILURE
        mCallback.onFailure(e)
    }

    fun stop() {
        mProgress.status = DownloadProgress.PAUSE
    }

}





